home *** CD-ROM | disk | FTP | other *** search
/ CD Concept 6 / CD Concept 06.iso / mac / UTILITAIRE / Little Smalltalk v3.1.4 / C Source / Sources / parser.c < prev    next >
Text File  |  1994-09-14  |  22KB  |  857 lines

  1. /* 
  2.     Little Smalltalk, version 2
  3.     Written by Tim Budd, Oregon State University, July 1987
  4.  
  5.     Method parser - parses the textual description of a method,
  6.     generating bytecodes and literals.
  7.  
  8.     This parser is based around a simple minded recursive descent
  9.     parser.
  10.     It is used both by the module that builds the initial virtual image,
  11.     and by a primitive when invoked from a running Smalltalk system.
  12.  
  13.     The latter case could, if the bytecode interpreter were fast enough,
  14.     be replaced by a parser written in Smalltalk.  This would be preferable,
  15.     but not if it slowed down the system too terribly.
  16.  
  17.     To use the parser the routine setInstanceVariables must first be
  18.     called with a class object.  This places the appropriate instance
  19.     variables into the memory buffers, so that references to them
  20.     can be correctly encoded.
  21.  
  22.     As this is recursive descent, you should read it SDRAWKCAB !
  23.         (from bottom to top)
  24. */
  25. # include <stdio.h>
  26. # include <string.h>
  27. # include <ctype.h>
  28. # include "env.h"
  29. # include "memory.h"
  30. # include "names.h"
  31. # include "interp.h"
  32. # include "lex.h"
  33. # ifdef STRING
  34. # include <string.h>
  35. # endif
  36. # ifdef STRINGS
  37. # include <strings.h>
  38. # endif
  39.  
  40.         /* all of the following limits could be increased (up to
  41.             256) without any trouble.  They are kept low 
  42.             to keep memory utilization down */
  43.  
  44. # define codeLimit 256        /* maximum number of bytecodes permitted */
  45. # define literalLimit 128    /* maximum number of literals permitted */
  46. # define temporaryLimit 32    /* maximum number of temporaries permitted */
  47. # define argumentLimit 32    /* maximum number of arguments permitted */
  48. # define instanceLimit 32    /* maximum number of instance vars permitted */
  49. # define methodLimit 64        /* maximum number of methods permitted */
  50.  
  51. #ifdef THINKC
  52. # include "memory.proto.h"
  53. # include "parser.proto.h"
  54. # include "lex.proto.h"
  55. # include "news.proto.h"
  56. # ifdef TCL
  57. #   include "tclprim.proto.h"
  58. # else
  59. #   include "winprim.proto.h"
  60. # endif
  61. #else
  62.  static genCode(int value);
  63.  static genInstruction(int high, int low);
  64.  static int genLiteral(object aLiteral);
  65.  static genInteger(int val);
  66.  static boolean nameTerm(char *name);
  67.  static int parseArray(void);
  68.  static boolean term(void);
  69.  static parsePrimitive(void);
  70.  static genMessage(boolean toSuper, int argumentCount, object messagesym);
  71.  static boolean unaryContinuation(boolean superReceiver);
  72.  static boolean binaryContinuation(boolean superReceiver);
  73.  static int optimizeBlock(int instruction, boolean dopop);
  74.  static boolean keyContinuation(boolean superReceiver);
  75.  static continuation(boolean superReceiver);
  76.  static expression(void);
  77.  static assignment(char *name);
  78.  static statement(void); 
  79.  static body(void);
  80.  static block(void);
  81.  static temporaries(void);
  82.  static messagePattern(void);
  83.  
  84.  static genCode(int);
  85.  static genInstruction(int, int);
  86.  static int genLiteral(object);
  87.  static genInteger(int);
  88.  static boolean nameTerm(char *);
  89.  static int parseArray(void);
  90.  static boolean term(void);
  91.  static parsePrimitive(void);
  92.  static genMessage(boolean, int, object);
  93.  static boolean unaryContinuation(boolean);
  94.  static boolean binaryContinuation(boolean);
  95.  static int optimizeBlock(int, boolean);
  96.  static boolean keyContinuation(boolean);
  97.  static continuation(boolean);
  98.  static expression(void);
  99.  static assignment(char *);
  100.  static statement(void);
  101.  static body(void);
  102.  static block(void);
  103.  static temporaries(void);
  104.  static messagePattern(void);
  105. #endif
  106.  
  107. boolean parseok;            /* parse still ok? */
  108. extern char peek();
  109. static int codeTop;            /* top position filled in code array */
  110. static byte codeArray[codeLimit];    /* bytecode array */
  111. static int literalTop;            /*  ... etc. */
  112. static object literalArray[literalLimit];
  113. static int temporaryTop;
  114. static char *temporaryName[temporaryLimit];
  115. static int argumentTop;
  116. static char *argumentName[argumentLimit];
  117. static int instanceTop;
  118. static char *instanceName[instanceLimit];
  119.  
  120. static int maxTemporary;        /* highest temporary see so far */
  121. static char selector[80];        /* message selector */
  122.  
  123. enum blockstatus {NotInBlock, InBlock, OptimizedBlock} blockstat;
  124.  
  125. void setInstanceVariables(object aClass)
  126. {    int i, limit;
  127.     object vars;
  128.  
  129.     if (aClass == nilobj)
  130.         instanceTop = 0;
  131.     else {
  132.         setInstanceVariables(basicAt(aClass, superClassInClass));
  133.         vars = basicAt(aClass, variablesInClass);
  134.         if (vars != nilobj) {
  135.             limit = sizeField(vars);
  136.             for (i = 1; i <= limit; i++)
  137.                 instanceName[++instanceTop] = charPtr(basicAt(vars, i));
  138.             }
  139.         }
  140. }
  141.  
  142. static void genCode(int value)
  143. {
  144.     if (codeTop >= codeLimit)
  145.         compilError(selector,"too many bytecode instructions in method","");
  146.     else
  147.         codeArray[codeTop++] = value;
  148. }
  149.  
  150. static void genInstruction(int high, int low)
  151. {
  152.     if (low >= 16) {
  153.         genInstruction(Extended, high);
  154.         genCode(low);
  155.         }
  156.     else
  157.         genCode(high * 16 + low);
  158. }
  159.  
  160. static int genLiteral(object aLiteral)
  161. {
  162.     if (literalTop >= literalLimit)
  163.         compilError(selector,"too many literals in method","");
  164.     else {
  165.         literalArray[++literalTop] = aLiteral;
  166.         incr(aLiteral);
  167.         }
  168.     return(literalTop - 1);
  169. }
  170.  
  171. static void genInteger(int val)
  172. {
  173.     if (val == -1)
  174.         genInstruction(PushConstant, minusOne);
  175.     else if ((val >= 0) && (val <= 2))
  176.         genInstruction(PushConstant, val);
  177.     else
  178.         genInstruction(PushLiteral,
  179.             genLiteral(newInteger(val)));
  180. }
  181.  
  182. static char *glbsyms[] = {"currentInterpreter", "nil", "true", "false",
  183. 0 };
  184.  
  185. static boolean nameTerm(char *name)
  186. {    int i;
  187.     boolean done = false;
  188.     boolean isSuper = false;
  189.  
  190.     /* it might be self or super */
  191.     if (streq(name, "self") || streq(name, "super")) {
  192.         genInstruction(PushArgument, 0);
  193.         done = true;
  194.         if (streq(name,"super")) isSuper = true;
  195.         }
  196.  
  197.     /* or it might be a temporary (reverse this to get most recent first)*/
  198.     if (! done)
  199.         for (i = temporaryTop; (! done) && ( i >= 1 ) ; i--)
  200.             if (streq(name, temporaryName[i])) {
  201.                 genInstruction(PushTemporary, i-1);
  202.                 done = true;
  203.                 }
  204.  
  205.     /* or it might be an argument */
  206.     if (! done)
  207.         for (i = 1; (! done) && (i <= argumentTop ) ; i++)
  208.             if (streq(name, argumentName[i])) {
  209.                 genInstruction(PushArgument, i);
  210.                 done = true;
  211.                 }
  212.  
  213.     /* or it might be an instance variable */
  214.     if (! done)
  215.         for (i = 1; (! done) && (i <= instanceTop); i++) {
  216.             if (streq(name, instanceName[i])) {
  217.                 genInstruction(PushInstance, i-1);
  218.                 done = true;
  219.                 }
  220.             }
  221.  
  222.     /* or it might be a global constant */
  223.     if (! done)
  224.         for (i = 0; (! done) && glbsyms[i]; i++)
  225.             if (streq(name, glbsyms[i])) {
  226.                 genInstruction(PushConstant, i+4);
  227.                 done = true;
  228.                 }
  229.  
  230.     /* not anything else, it must be a global */
  231.     /* must look it up at run time */
  232.     if (! done) {
  233.         genInstruction(PushLiteral, genLiteral(newSymbol(name)));
  234.         genMessage(false, 0, newSymbol("value"));
  235.         }
  236.  
  237.     return(isSuper);
  238. }
  239.  
  240. static int parseArray(void)
  241. {    int i, size, base;
  242.     object newLit, obj;
  243.  
  244.     base = literalTop;
  245.     ignore nextToken();
  246.     while (parseok && (token != closing)) {
  247.         switch(token) {
  248.             case arraybegin:
  249.                 ignore parseArray();
  250.                 break;
  251.  
  252.             case intconst:
  253.                 ignore genLiteral(newInteger(tokenInteger));
  254.                 ignore nextToken();
  255.                 break;
  256.  
  257.             case floatconst:
  258.                 ignore genLiteral(newFloat(tokenFloat));
  259.                 ignore nextToken();
  260.                 break;
  261.  
  262.             case nameconst: case namecolon: case symconst:
  263.                 ignore genLiteral(newSymbol(tokenString));
  264.                 ignore nextToken();
  265.                 break;
  266.  
  267.             case binary:
  268.                 if (streq(tokenString, "(")) {
  269.                     ignore parseArray();
  270.                     break;
  271.                     }
  272.                 if (streq(tokenString, "-") && isdigit(peek())) {
  273.                     ignore nextToken();
  274.                     if (token == intconst)
  275.                         ignore genLiteral(newInteger(- tokenInteger));
  276.                     else if (token == floatconst) {
  277.                         ignore genLiteral(newFloat(-tokenFloat));
  278.                         }
  279.                     else
  280.                         compilError(selector,"negation not followed",
  281.                             "by number");
  282.                     ignore nextToken();
  283.                     break;
  284.                     }
  285.                 ignore genLiteral(newSymbol(tokenString));
  286.                 ignore nextToken();
  287.                 break;
  288.  
  289.             case charconst:
  290.                 ignore genLiteral(newChar( tokenInteger));
  291.                 ignore nextToken();
  292.                 break;
  293.  
  294.             case strconst:
  295.                 ignore genLiteral(newStString(tokenString));
  296.                 ignore nextToken();
  297.                 break;
  298.  
  299.             default:
  300.                 compilError(selector,"illegal text in literal array",
  301.                     tokenString);
  302.                 ignore nextToken();
  303.                 break;
  304.         }
  305.     }
  306.  
  307.     if (parseok)
  308.         if (! streq(tokenString, ")"))
  309.             compilError(selector,"array not terminated by right parenthesis",
  310.                 tokenString);
  311.         else
  312.             ignore nextToken();
  313.     size = literalTop - base;
  314.     newLit = newArray(size);
  315.     for (i = size; i >= 1; i--) {
  316.         obj = literalArray[literalTop];
  317.         basicAtPut(newLit, i, obj);
  318.         decr(obj);
  319.         literalArray[literalTop] = nilobj;
  320.         literalTop = literalTop - 1;
  321.         }
  322.     return(genLiteral(newLit));
  323. }
  324.  
  325. static boolean term(void)
  326. {    boolean superTerm = false;    /* true if term is pseudo var super */
  327.  
  328.     if (token == nameconst) {
  329.         superTerm = nameTerm(tokenString);
  330.         ignore nextToken();
  331.         }
  332.     else if (token == intconst) {
  333.         genInteger(tokenInteger);
  334.         ignore nextToken();
  335.         }
  336.     else if (token == floatconst) {
  337.         genInstruction(PushLiteral, genLiteral(newFloat(tokenFloat)));
  338.         ignore nextToken();
  339.         }
  340.     else if ((token == binary) && streq(tokenString, "-")) {
  341.         ignore nextToken();
  342.         if (token == intconst)
  343.             genInteger(- tokenInteger);
  344.         else if (token == floatconst) {
  345.             genInstruction(PushLiteral,
  346.                 genLiteral(newFloat(-tokenFloat)));
  347.             }
  348.         else
  349.             compilError(selector,"negation not followed",
  350.                 "by number");
  351.         ignore nextToken();
  352.         }
  353.     else if (token == charconst) {
  354.         genInstruction(PushLiteral,
  355.             genLiteral(newChar(tokenInteger)));
  356.         ignore nextToken();
  357.         }
  358.     else if (token == symconst) {
  359.         genInstruction(PushLiteral,
  360.             genLiteral(newSymbol(tokenString)));
  361.         ignore nextToken();
  362.         }
  363.     else if (token == strconst) {
  364.         genInstruction(PushLiteral,
  365.             genLiteral(newStString(tokenString)));
  366.         ignore nextToken();
  367.         }
  368.     else if (token == arraybegin) {
  369.         genInstruction(PushLiteral, parseArray());
  370.         }
  371.     else if ((token == binary) && streq(tokenString, "(")) {
  372.         ignore nextToken();
  373.         expression();
  374.         if (parseok)
  375.             if ((token != closing) || ! streq(tokenString, ")"))
  376.                 compilError(selector,"Missing Right Parenthesis","");
  377.             else
  378.                 ignore nextToken();
  379.         }
  380.     else if ((token == binary) && streq(tokenString, "<"))
  381.         parsePrimitive();
  382.     else if ((token == binary) && streq(tokenString, "["))
  383.         block();
  384.     else
  385.         compilError(selector,"invalid expression start", tokenString);
  386.  
  387.     return(superTerm);
  388. }
  389.  
  390. static void parsePrimitive(void)
  391. {    int primitiveNumber, argumentCount;
  392.  
  393.     if (nextToken() != intconst)
  394.         compilError(selector,"primitive number missing","");
  395.     primitiveNumber = tokenInteger;
  396.     ignore nextToken();
  397.     argumentCount = 0;
  398.     while (parseok && ! ((token == binary) && streq(tokenString, ">"))) {
  399.         ignore term();
  400.         argumentCount++;
  401.         }
  402.     genInstruction(DoPrimitive, argumentCount);
  403.     genCode(primitiveNumber);
  404.     ignore nextToken();
  405. }
  406.  
  407. static void genMessage(boolean toSuper, int argumentCount, object messagesym)
  408. {    boolean sent = false;
  409.     int i;
  410.  
  411.     if ((! toSuper) && (argumentCount == 0))
  412.         for (i = 0; (! sent) && unSyms[i] ; i++)
  413.             if (messagesym == unSyms[i]) {
  414.                 genInstruction(SendUnary, i);
  415.                 sent = true;
  416.                 }
  417.  
  418.     if ((! toSuper) && (argumentCount == 1))
  419.         for (i = 0; (! sent) && binSyms[i]; i++)
  420.             if (messagesym == binSyms[i]) {
  421.                 genInstruction(SendBinary, i);
  422.                 sent = true;
  423.                 }
  424.  
  425.     if (! sent) {
  426.         genInstruction(MarkArguments, 1 + argumentCount);
  427.         if (toSuper) {
  428.             genInstruction(DoSpecial, SendToSuper);
  429.             genCode(genLiteral(messagesym));
  430.             }
  431.         else
  432.             genInstruction(SendMessage, genLiteral(messagesym));
  433.         }
  434. }
  435.  
  436. static boolean unaryContinuation(boolean superReceiver)
  437. {    int i;
  438.     boolean sent;
  439.  
  440.     while (parseok && (token == nameconst)) {
  441.         /* first check to see if it could be a temp by mistake */
  442.         for (i=1; i < temporaryTop; i++)
  443.             if (streq(tokenString, temporaryName[i]))
  444.                 compilWarn(selector,"message same as temporary:",
  445.                     tokenString);
  446.         for (i=1; i < argumentTop; i++)
  447.             if (streq(tokenString, argumentName[i]))
  448.                 compilWarn(selector,"message same as argument:",
  449.                     tokenString);
  450.         /* the next generates too many spurious messages */
  451.         /* for (i=1; i < instanceTop; i++)
  452.             if (streq(tokenString, instanceName[i]))
  453.                 compilWarn(selector,"message same as instance",
  454.                     tokenString); */
  455.  
  456.         sent = false;
  457.  
  458.         if (! sent) {
  459.             genMessage(superReceiver, 0, newSymbol(tokenString));
  460.             }
  461.         /* once a message is sent to super, reciever is not super */
  462.         superReceiver = false;
  463.         ignore nextToken();
  464.         }
  465.     return(superReceiver);
  466. }
  467.  
  468. static boolean binaryContinuation(boolean superReceiver)
  469. {    boolean superTerm;
  470.     object messagesym;
  471.  
  472.     superReceiver = unaryContinuation(superReceiver);
  473.     while (parseok && (token == binary)) {
  474.         messagesym = newSymbol(tokenString);
  475.         ignore nextToken();
  476.         superTerm = term();
  477.         ignore unaryContinuation(superTerm);
  478.         genMessage(superReceiver, 1, messagesym);
  479.         superReceiver = false;
  480.         }
  481.     return(superReceiver);
  482. }
  483.  
  484. static int optimizeBlock(int instruction, boolean dopop)
  485. {    int location;
  486.     enum blockstatus savebstat;
  487.  
  488.     savebstat = blockstat;
  489.     genInstruction(DoSpecial, instruction);
  490.     location = codeTop;
  491.     genCode(0);
  492.     if (dopop)
  493.         genInstruction(DoSpecial, PopTop);
  494.     ignore nextToken();
  495.     if (streq(tokenString, "[")) {
  496.         ignore nextToken();
  497.         if (blockstat == NotInBlock)
  498.             blockstat = OptimizedBlock;
  499.         body();
  500.         if (! streq(tokenString, "]"))
  501.             compilError(selector,"missing close","after block");
  502.         ignore nextToken();
  503.         }
  504.     else {
  505.         ignore binaryContinuation(term());
  506.         genMessage(false, 0, newSymbol("value"));
  507.         }
  508.     codeArray[location] = codeTop+1;
  509.     blockstat = savebstat;
  510.     return(location);
  511. }
  512.  
  513. static boolean keyContinuation(boolean superReceiver)
  514. {    int i, j, argumentCount;
  515.     boolean sent, superTerm;
  516.     object messagesym;
  517.     char pattern[80];
  518.  
  519.     superReceiver = binaryContinuation(superReceiver);
  520.     if (token == namecolon) {
  521.         if (streq(tokenString, "ifTrue:")) {
  522.             i = optimizeBlock(BranchIfFalse, false);
  523.             if (streq(tokenString, "ifFalse:")) {
  524.                 codeArray[i] = codeTop + 3;
  525.                 ignore optimizeBlock(Branch, true);
  526.                 }
  527.             }
  528.         else if (streq(tokenString, "ifFalse:")) {
  529.             i = optimizeBlock(BranchIfTrue, false);
  530.             if (streq(tokenString, "ifTrue:")) {
  531.                 codeArray[i] = codeTop + 3;
  532.                 ignore optimizeBlock(Branch, true);
  533.                 }
  534.             }
  535.         else if (streq(tokenString, "whileTrue:")) {
  536.             j = codeTop;
  537.             genInstruction(DoSpecial, Duplicate);
  538.             genMessage(false, 0, newSymbol("value"));
  539.             i = optimizeBlock(BranchIfFalse, false);
  540.             genInstruction(DoSpecial, PopTop);
  541.             genInstruction(DoSpecial, Branch);
  542.             genCode(j+1);
  543.             codeArray[i] = codeTop+1;
  544.             genInstruction(DoSpecial, PopTop);
  545.             }
  546.         else if (streq(tokenString, "and:"))
  547.             ignore optimizeBlock(AndBranch, false);
  548.         else if (streq(tokenString, "or:"))
  549.             ignore optimizeBlock(OrBranch, false);
  550.         else {
  551.             pattern[0] = '\0';
  552.             argumentCount = 0;
  553.             while (parseok && (token == namecolon)) {
  554.                 ignore strcat(pattern, tokenString);
  555.                 argumentCount++;
  556.                 ignore nextToken();
  557.                 superTerm = term();
  558.                 ignore binaryContinuation(superTerm);
  559.                 }
  560.             sent = false;
  561.  
  562.             /* check for predefined messages */
  563.             messagesym = newSymbol(pattern);
  564.  
  565.             if (! sent) {
  566.                 genMessage(superReceiver, argumentCount, messagesym);
  567.                 }
  568.             }
  569.         superReceiver = false;
  570.         }
  571.     return(superReceiver);
  572. }
  573.  
  574. static void continuation(boolean superReceiver)
  575. {
  576.     superReceiver = keyContinuation(superReceiver);
  577.  
  578.     while (parseok && (token == closing) && streq(tokenString, ";")) {
  579.         genInstruction(DoSpecial, Duplicate);
  580.         ignore nextToken();
  581.         ignore keyContinuation(superReceiver);
  582.         genInstruction(DoSpecial, PopTop);
  583.         }
  584. }
  585.  
  586. static void expression(void)
  587. {    boolean superTerm;
  588.     char assignname[60];
  589.  
  590.     if (token == nameconst) {    /* possible assignment */
  591.         ignore strcpy(assignname, tokenString);
  592.         ignore nextToken();
  593.         if ((token == binary) && streq(tokenString, "<-")) {
  594.             ignore nextToken();
  595.             assignment(assignname);
  596.             }
  597.         else {        /* not an assignment after all */
  598.             superTerm = nameTerm(assignname);
  599.             continuation(superTerm);
  600.             }
  601.         }
  602.     else {
  603.         superTerm = term();
  604.         if (parseok)
  605.             continuation(superTerm);
  606.         }
  607. }
  608.  
  609. static void assignment(char *name)
  610. {    int i;
  611.     boolean done;
  612.  
  613.     done = false;
  614.  
  615.     /* it might be a temporary */
  616.     for (i = temporaryTop; (! done) && (i > 0); i--)
  617.         if (streq(name, temporaryName[i])) {
  618.             expression();
  619.             genInstruction(AssignTemporary, i-1);
  620.             done = true;
  621.             }
  622.  
  623.     /* or it might be an instance variable */
  624.     for (i = 1; (! done) && (i <= instanceTop); i++)
  625.         if (streq(name, instanceName[i])) {
  626.             expression();
  627.             genInstruction(AssignInstance, i-1);
  628.             done = true;
  629.             }
  630.  
  631.     if (! done) {    /* not known, handle at run time */
  632.         genInstruction(PushArgument, 0);
  633.         genInstruction(PushLiteral, genLiteral(newSymbol(name)));
  634.         expression();
  635.         genMessage(false, 2, newSymbol("assign:value:"));
  636.         }
  637. }
  638.  
  639. static void statement(void)
  640. {
  641.  
  642.     if ((token == binary) && streq(tokenString, "^")) {
  643.         ignore nextToken();
  644.         expression();
  645.         if (blockstat == InBlock) {
  646.             /* change return point before returning */
  647.             genInstruction(PushConstant, contextConst);
  648.             genMessage(false, 0, newSymbol("blockReturn"));
  649.             genInstruction(DoSpecial, PopTop);
  650.             }
  651.         genInstruction(DoSpecial, StackReturn);
  652.         }
  653.     else {
  654.         expression();
  655.         }
  656. }
  657.  
  658. static void body(void)
  659. {
  660.     /* empty blocks are same as nil */
  661.     if ((blockstat == InBlock) || (blockstat == OptimizedBlock))
  662.         if ((token == closing) && streq(tokenString, "]")) {
  663.             genInstruction(PushConstant, nilConst);
  664.             return;
  665.             }
  666.  
  667.     while(parseok) {
  668.         statement();
  669.         if (token == closing)
  670.             if (streq(tokenString,".")) {
  671.                 ignore nextToken();
  672.                 if (token == inputend)
  673.                     break;
  674.                 else  /* pop result, go to next statement */
  675.                     genInstruction(DoSpecial, PopTop);
  676.                 }
  677.             else
  678.                 break;    /* leaving result on stack */
  679.         else
  680.             if (token == inputend)
  681.                 break;    /* leaving result on stack */
  682.         else {
  683.             compilError(selector,"invalid statement ending; token is ",
  684.                 tokenString);
  685.             }
  686.         }
  687. }
  688.  
  689. static void block(void)
  690. {    int saveTemporary, argumentCount, fixLocation;
  691.     object tempsym, newBlk;
  692.     enum blockstatus savebstat;
  693.  
  694.     saveTemporary = temporaryTop;
  695.     savebstat = blockstat;
  696.     argumentCount = 0;
  697.     ignore nextToken();
  698.     if ((token == binary) && streq(tokenString, ":")) {
  699.         while (parseok && (token == binary) && streq(tokenString,":")) {
  700.             if (nextToken() != nameconst)
  701.                 compilError(selector,"name must follow colon",
  702.                     "in block argument list");
  703.                 if (++temporaryTop > maxTemporary)
  704.                 maxTemporary = temporaryTop;
  705.             argumentCount++;
  706.             if (temporaryTop > temporaryLimit)
  707.                 compilError(selector,"too many temporaries in method","");
  708.             else {
  709.                 tempsym = newSymbol(tokenString);
  710.                 temporaryName[temporaryTop] = charPtr(tempsym);
  711.                 }
  712.             ignore nextToken();
  713.             }
  714.         if ((token != binary) || ! streq(tokenString, "|"))
  715.             compilError(selector,"block argument list must be terminated",
  716.                     "by |");
  717.         ignore nextToken();
  718.         }
  719.     newBlk = newBlock();
  720.     basicAtPut(newBlk, argumentCountInBlock, newInteger(argumentCount));
  721.     basicAtPut(newBlk, argumentLocationInBlock, 
  722.         newInteger(saveTemporary + 1));
  723.     genInstruction(PushLiteral, genLiteral(newBlk));
  724.     genInstruction(PushConstant, contextConst);
  725.     genInstruction(DoPrimitive, 2);
  726.     genCode(29);
  727.     genInstruction(DoSpecial, Branch);
  728.     fixLocation = codeTop;
  729.     genCode(0);
  730.     /*genInstruction(DoSpecial, PopTop);*/
  731.     basicAtPut(newBlk, bytecountPositionInBlock, newInteger(codeTop+1));
  732.     blockstat = InBlock;
  733.     body();
  734.     if ((token == closing) && streq(tokenString, "]"))
  735.         ignore nextToken();
  736.     else
  737.         compilError(selector,"block not terminated by ]","");
  738.     genInstruction(DoSpecial, StackReturn);
  739.     codeArray[fixLocation] = codeTop+1;
  740.     temporaryTop = saveTemporary;
  741.     blockstat = savebstat;
  742. }
  743.  
  744. static void temporaries(void)
  745. {    object tempsym;
  746.  
  747.     temporaryTop = 0;
  748.     if ((token == binary) && streq(tokenString, "|")) {
  749.         ignore nextToken();
  750.         while (token == nameconst) {
  751.             if (++temporaryTop > maxTemporary)
  752.                 maxTemporary = temporaryTop;
  753.             if (temporaryTop > temporaryLimit)
  754.                 compilError(selector,"too many temporaries in method","");
  755.             else {
  756.                 tempsym = newSymbol(tokenString);
  757.                 temporaryName[temporaryTop] = charPtr(tempsym);
  758.                 }
  759.             ignore nextToken();
  760.             }
  761.         if ((token != binary) || ! streq(tokenString, "|"))
  762.             compilError(selector,"temporary list not terminated by bar","");
  763.         else
  764.             ignore nextToken();
  765.         }
  766. }
  767.  
  768. static void messagePattern(void)
  769. {    object argsym;
  770.  
  771.     argumentTop = 0;
  772.     ignore strcpy(selector, tokenString);
  773.     if (token == nameconst)        /* unary message pattern */
  774.         ignore nextToken();
  775.     else if (token == binary) {    /* binary message pattern */
  776.         ignore nextToken();
  777.         if (token != nameconst) 
  778.             compilError(selector,"binary message pattern not followed by name",selector);
  779.         argsym = newSymbol(tokenString);
  780.         argumentName[++argumentTop] = charPtr(argsym);
  781.         ignore nextToken();
  782.         }
  783.     else if (token == namecolon) {    /* keyword message pattern */
  784.         selector[0] = '\0';
  785.         while (parseok && (token == namecolon)) {
  786.             ignore strcat(selector, tokenString);
  787.             ignore nextToken();
  788.             if (token != nameconst)
  789.                 compilError(selector,"keyword message pattern",
  790.                     "not followed by a name");
  791.             if (++argumentTop > argumentLimit)
  792.                 compilError(selector,"too many arguments in method","");
  793.             argsym = newSymbol(tokenString);
  794.             argumentName[argumentTop] = charPtr(argsym);
  795.             ignore nextToken();
  796.             }
  797.         }
  798.     else
  799.         compilError(selector,"illegal message selector", tokenString);
  800. }
  801.  
  802. boolean parse(object method, char *text, boolean savetext)
  803. {    int i;
  804.     object bytecodes, theLiterals;
  805.     byte *bp;
  806.  
  807.     lexinit(text);
  808.     parseok = true;
  809.     blockstat = NotInBlock;
  810.     codeTop = 0;
  811.     literalTop = temporaryTop = argumentTop =0;
  812.     maxTemporary = 0;
  813.  
  814.     messagePattern();
  815.     if (parseok)
  816.         temporaries();
  817.     if (parseok)
  818.         body();
  819.     if (parseok) {
  820.         genInstruction(DoSpecial, PopTop);
  821.         genInstruction(DoSpecial, SelfReturn);
  822.         }
  823.  
  824.     if (! parseok) {
  825.         basicAtPut(method, bytecodesInMethod, nilobj);
  826.         }
  827.     else {
  828.         bytecodes = newByteArray(codeTop);
  829.         bp = bytePtr(bytecodes);
  830.         for (i = 0; i < codeTop; i++) {
  831.             bp[i] = codeArray[i];
  832.             }
  833.         basicAtPut(method, messageInMethod, newSymbol(selector));
  834.         basicAtPut(method, bytecodesInMethod, bytecodes);
  835.         if (literalTop > 0) {
  836.             theLiterals = newArray(literalTop);
  837.             for (i = 1; i <= literalTop; i++) {
  838.                 basicAtPut(theLiterals, i, literalArray[i]);
  839.                 decr(literalArray[i]);
  840.                 }
  841.             basicAtPut(method, literalsInMethod, theLiterals);
  842.             }
  843.         else {
  844.             basicAtPut(method, literalsInMethod, nilobj);
  845.             }
  846.         basicAtPut(method, stackSizeInMethod, newInteger(6));
  847.         basicAtPut(method, temporarySizeInMethod,
  848.             newInteger(1 + maxTemporary));
  849.         if (savetext) {
  850.             basicAtPut(method, textInMethod, newStString(text));
  851.             }
  852.         return(true);
  853.         }
  854.     return(false);
  855. }
  856.  
  857.